/*
 * @(#)AtnaRegistryService.java
 * Date 2014-01-18
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.registry.service;

import java.math.BigInteger;

import javax.enterprise.context.ApplicationScoped;

import javax.inject.Inject;

import oasis.names.tc.ebxml_regrep.xsd.lcm._3.SubmitObjectsRequest;

import oasis.names.tc.ebxml_regrep.xsd.query._3.AdhocQueryRequest;
import oasis.names.tc.ebxml_regrep.xsd.query._3.AdhocQueryResponse;

import oasis.names.tc.ebxml_regrep.xsd.rim._3.AdhocQueryType;

import oasis.names.tc.ebxml_regrep.xsd.rs._3.RegistryResponseType;

import org.apache.commons.lang3.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.hornerscorners.lamppost.atna.client.AtnaContext;
import us.hornerscorners.lamppost.atna.client.IAtnaClient;

import us.hornerscorners.lamppost.atna.client.utils.AtnaUtils;

import us.hornerscorners.lamppost.hl7v3common.utils.HL7Utils;

import us.hornerscorners.lamppost.model.audit.AuditContext;
import us.hornerscorners.lamppost.model.audit.AuditMessage;
import us.hornerscorners.lamppost.model.audit.EventIdentificationType;
import us.hornerscorners.lamppost.model.audit.ParticipantObjectIdentificationType;

import us.hornerscorners.lamppost.model.document.SubmissionSet;

import us.hornerscorners.lamppost.model.patient.PatientIdentity;

import us.hornerscorners.lamppost.registry.constant.Metadata;
import us.hornerscorners.lamppost.registry.constant.ResponseStatus;

import us.hornerscorners.lamppost.utils.MarshallUtils;


/**
 * Class description
 *
 *
 * @version        v1.0, 2014-01-18
 * @author         Jim Horner
 */
@ApplicationScoped
public class AtnaRegistryService {

    /** Field description */
    @Inject
    private IAtnaClient atnaClient;

    /** Field description */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    /** Field description */
    @Inject
    private SimpleXDSParser xdsParser;

    /**
     * Constructs ...
     *
     *
     */
    public AtnaRegistryService() {

        super();
    }

    /**
     * Method description
     *
     *
     * @param auditContext
     * @param request
     * @param response
     */
    public void sendQueryReceivedAuditMessage(AuditContext auditContext,
            AdhocQueryRequest request, AdhocQueryResponse response) {

        String pidcx = this.xdsParser.parsePatientCX(request.getAdhocQuery());

        sendQueryReceivedAuditMessage(auditContext, request, response, pidcx);
    }

    /**
     * ITI-2a 3.18 Registry Store Query
     * Document Registry Audit Message
     *
     * @param auditContext
     * @param request
     * @param response
     * @param cxPatientId
     */
    public void sendQueryReceivedAuditMessage(AuditContext auditContext,
            AdhocQueryRequest request, AdhocQueryResponse response, String cxPatientId) {

        if (this.atnaClient.isEnabled()) {

            try {

                AuditMessage msg = new AuditMessage();
                AtnaContext atnaContext = this.atnaClient.getAtnaContext();

                boolean success = false;

                if (response != null) {

                    success =
                        ResponseStatus.Success.getCode().equals(response.getStatus());
                }

                EventIdentificationType event = new EventIdentificationType();

                event.setEventID(AtnaUtils.createCodedValue("110112", "DCM", "Query"));
                event.setEventActionCode("E");
                event.setEventDateTime(AtnaUtils.createTimeStamp());
                event.setEventOutcomeIndicator(success
                                               ? BigInteger.ONE : BigInteger.ZERO);
                event.getEventTypeCode().add(auditContext.getEventType());
                msg.setEventIdentification(event);

                // Sender
                msg.getActiveParticipant().add(
                    AtnaUtils.createSourceParticipant(auditContext));

                // Receiver
                msg.getActiveParticipant().add(
                    AtnaUtils.createDestinationParticipant(atnaContext, auditContext));

                // Source
                msg.getAuditSourceIdentification().add(
                    AtnaUtils.createAuditSource(auditContext));

                AdhocQueryType adhocQuery = request.getAdhocQuery();

                // Patient
                if (StringUtils.isNotBlank(cxPatientId)) {

                    msg.getParticipantObjectIdentification().add(
                        AtnaUtils.createPatientIdentification(cxPatientId));
                }

                // Query
                ParticipantObjectIdentificationType query =
                    new ParticipantObjectIdentificationType();

                query.setParticipantObjectTypeCode(Short.valueOf("2"));
                query.setParticipantObjectTypeCodeRole(Short.valueOf("24"));
                query.setParticipantObjectIDTypeCode(auditContext.getEventType());

                query.setParticipantObjectID(adhocQuery.getId());
                query.setParticipantObjectName(adhocQuery.getHome());
                query.setParticipantObjectQuery(MarshallUtils.marshall(request,
                        AdhocQueryRequest.class).getBytes());
                query.getParticipantObjectDetail().add(AtnaUtils.createUTF8Detail());
                msg.getParticipantObjectIdentification().add(query);

                this.atnaClient.sendAuditEvent(msg);

            } catch (Exception e) {

                logger.error("Exception sending ATNA", e);
            }
        }
    }

    /**
     * ITI-2a 3.18 Registry Store Query
     * Document Consumer Audit Message
     *
     * @param auditContext
     * @param request
     * @param response
     */
    public void sendQueryRequestAuditMessage(AuditContext auditContext,
            AdhocQueryRequest request, AdhocQueryResponse response) {

        if (this.atnaClient.isEnabled()) {

            try {

                AuditMessage msg = new AuditMessage();
                AtnaContext atnaContext = this.atnaClient.getAtnaContext();

                boolean success = false;

                if (response != null) {

                    success =
                        ResponseStatus.Success.getCode().equals(response.getStatus());
                }

                EventIdentificationType event = new EventIdentificationType();

                event.setEventID(AtnaUtils.createCodedValue("110112", "DCM", "Query"));
                event.setEventActionCode("E");
                event.setEventDateTime(AtnaUtils.createTimeStamp());
                event.setEventOutcomeIndicator(success
                                               ? BigInteger.ONE : BigInteger.ZERO);
                event.getEventTypeCode().add(auditContext.getEventType());
                msg.setEventIdentification(event);

                // Sender
                msg.getActiveParticipant().add(
                    AtnaUtils.createClientSourceParticipant(atnaContext, auditContext));

                // Receiver
                msg.getActiveParticipant().add(
                    AtnaUtils.createClientDestinationParticipant(auditContext));

                // Source
                msg.getAuditSourceIdentification().add(
                    AtnaUtils.createAuditSource(auditContext));

                AdhocQueryType adhocQuery = request.getAdhocQuery();

                // Patient
                String cxPatientId = this.xdsParser.parsePatientCX(adhocQuery);

                if (StringUtils.isNotBlank(cxPatientId)) {

                    msg.getParticipantObjectIdentification().add(
                        AtnaUtils.createPatientIdentification(cxPatientId));
                }

                // Query
                ParticipantObjectIdentificationType query =
                    new ParticipantObjectIdentificationType();

                query.setParticipantObjectTypeCode(Short.valueOf("2"));
                query.setParticipantObjectTypeCodeRole(Short.valueOf("24"));
                query.setParticipantObjectIDTypeCode(auditContext.getEventType());

                query.setParticipantObjectID(adhocQuery.getId());
                query.setParticipantObjectName(adhocQuery.getHome());
                query.setParticipantObjectQuery(MarshallUtils.marshall(request,
                        AdhocQueryRequest.class).getBytes());
                query.getParticipantObjectDetail().add(AtnaUtils.createUTF8Detail());
                msg.getParticipantObjectIdentification().add(query);

                this.atnaClient.sendAuditEvent(msg);

            } catch (Exception e) {

                logger.error("Exception sending ATNA", e);
            }
        }
    }

    /**
     * ITI-2b 3.42 Register Document Set-b
     * Document Registry Audit Message
     *
     * @param auditContext
     * @param patientIdentity
     * @param submissionSet
     * @param response
     */
    public void sendRegisterReceivedAuditMessage(AuditContext auditContext,
            PatientIdentity patientIdentity, SubmissionSet submissionSet,
            RegistryResponseType response) {

        if (this.atnaClient.isEnabled()) {

            try {

                AuditMessage msg = new AuditMessage();
                AtnaContext atnaContext = this.atnaClient.getAtnaContext();

                boolean success = false;

                if (response != null) {

                    success =
                        ResponseStatus.Success.getCode().equals(response.getStatus());
                }

                EventIdentificationType event = new EventIdentificationType();

                event.setEventID(AtnaUtils.createCodedValue("110107", "DCM", "Import"));
                event.setEventActionCode("C");
                event.setEventDateTime(AtnaUtils.createTimeStamp());
                event.setEventOutcomeIndicator(success
                                               ? BigInteger.ONE : BigInteger.ZERO);
                event.getEventTypeCode().add(auditContext.getEventType());
                msg.setEventIdentification(event);

                // Sender
                msg.getActiveParticipant().add(
                    AtnaUtils.createSourceParticipant(auditContext));

                // Receiver
                msg.getActiveParticipant().add(
                    AtnaUtils.createDestinationParticipant(atnaContext, auditContext));

                // Source
                msg.getAuditSourceIdentification().add(
                    AtnaUtils.createAuditSource(auditContext));

                // Patient
                if (patientIdentity != null) {

                    String pidcx = HL7Utils.toCXString(patientIdentity.getIdentifier());

                    msg.getParticipantObjectIdentification().add(
                        AtnaUtils.createPatientIdentification(pidcx));
                }

                if (submissionSet != null) {

                    ParticipantObjectIdentificationType ssobj =
                        new ParticipantObjectIdentificationType();

                    ssobj.setParticipantObjectTypeCode(Short.valueOf("2"));
                    ssobj.setParticipantObjectTypeCodeRole(Short.valueOf("20"));
                    ssobj.setParticipantObjectIDTypeCode(
                        AtnaUtils.createCodedValue(
                            Metadata.SubmissionSetClassificationNode.getURN(),
                            "IHE XDS Metadata", "submission set classificationNode"));
                    ssobj.setParticipantObjectID(submissionSet.getUniqueId().getRoot());
                    msg.getParticipantObjectIdentification().add(ssobj);
                }

                this.atnaClient.sendAuditEvent(msg);

            } catch (Exception e) {

                logger.error("Exception sending ATNA", e);
            }
        }
    }

    /**
     * ITI-2b 3.42 Register Document Set-b
     * Document Repository Audit Message
     * Integrated Document Source/Repository Audit Message
     *
     * @param auditContext
     * @param request
     * @param response
     */
    public void sendRegisterRequestAuditMessage(AuditContext auditContext,
            SubmitObjectsRequest request, RegistryResponseType response) {

        if (this.atnaClient.isEnabled()) {

            try {

                AuditMessage msg = new AuditMessage();
                AtnaContext atnaContext = this.atnaClient.getAtnaContext();

                boolean success = false;

                if (response != null) {

                    success =
                        ResponseStatus.Success.getCode().equals(response.getStatus());
                }

                EventIdentificationType event = new EventIdentificationType();

                event.setEventID(AtnaUtils.createCodedValue("110106", "DCM", "Export"));
                event.setEventActionCode("R");
                event.setEventDateTime(AtnaUtils.createTimeStamp());
                event.setEventOutcomeIndicator(success
                                               ? BigInteger.ONE : BigInteger.ZERO);
                event.getEventTypeCode().add(auditContext.getEventType());
                msg.setEventIdentification(event);

                // Sender
                msg.getActiveParticipant().add(
                    AtnaUtils.createClientSourceParticipant(atnaContext, auditContext));

                // Receiver
                msg.getActiveParticipant().add(
                    AtnaUtils.createClientDestinationParticipant(auditContext));

                // Source
                msg.getAuditSourceIdentification().add(
                    AtnaUtils.createAuditSource(auditContext));

                // Patient
                String pidcx = this.xdsParser.parsePatientCX(request);

                if (StringUtils.isNotBlank(pidcx)) {

                    msg.getParticipantObjectIdentification().add(
                        AtnaUtils.createPatientIdentification(pidcx));
                }

                // TODO is this fixable?
                // id is probably not a UUID but a symbolic id
                // SubmissionSet
                String subSetId = this.xdsParser.parseSubmissionSetId(request);

                if (StringUtils.isNotBlank(subSetId)) {

                    ParticipantObjectIdentificationType ssobj =
                        new ParticipantObjectIdentificationType();

                    ssobj.setParticipantObjectTypeCode(Short.valueOf("2"));
                    ssobj.setParticipantObjectTypeCodeRole(Short.valueOf("20"));
                    ssobj.setParticipantObjectIDTypeCode(
                        AtnaUtils.createCodedValue(
                            Metadata.SubmissionSetClassificationNode.getURN(),
                            "IHE XDS Metadata", "submission set classificationNode"));
                    ssobj.setParticipantObjectID(subSetId);
                    msg.getParticipantObjectIdentification().add(ssobj);
                }

                this.atnaClient.sendAuditEvent(msg);

            } catch (Exception e) {

                logger.error("Exception sending ATNA", e);
            }
        }
    }
}
